/**
 * RMI SERVER  - THE RACE RESERVATION SERVER IN THE ARCHITECTURE
 * CONNECTION TO: RMI AUTHORIZATION SERVER AND AUTHORIZATION WEB SERVICE
 * CONNECTION TO: CORBA RUNNING RACE SERVER COMPONENT
 * CONNECTION TO: ARABARACES WEB SERVICE
 * USE THE COMMAND INTERFACE TO KEEP A TRACE OF THE SERVER ACTIVITIES
 */
package raceReservationServer;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.RMISecurityManager;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
import java.util.List;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import raceReservationServer.dao.RaceServerDAO;
import raceReservationServer.loginGateway.AuthorizationGatewayFactory;
import raceReservationServer.loginGateway.IAuthorizeGateway;
import raceReservationServer.loginGateway.RunnerDO;
import raceReservationServer.loginGateway.RunnerRMIDTO;
import raceReservationServer.loginGateway.ValidationException;
import raceReservationServer.raceServerGateway.IRaceServerGateway;
import raceReservationServer.raceServerGateway.RaceServerGatewayFactory;
import raceReservationServer.saxParser.GatewayObject;
import raceReservationServer.saxParser.RaceServerGatewaysSAXHandler;
import corbaServer.RaceDO;
import corbaServer.dao.CorbaRaceServerDAO;
import raceReservationServer.RaceRMIDTO;
import util.observer.rmi.IRemoteObserver;
import util.observer.rmi.RemoteObservable;

public class ReservationRaceServer extends UnicastRemoteObject implements IReservationRaceServer{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	/**
	 * CACHE OF RaceRMIDTO objects, organized by Running Race Name To be
	 * loaded at the initialization process
	 */
	private TreeMap<String, Map<String, RaceRMIDTO>> racesCache = null;
	private Map<String, RaceRMIDTO> raceMap = null;
	private List<raceReservationServer.raceServerGateway.RaceDO> races = null;
	private RaceRMIDTO raceRmiDto = null;
	private RemoteObservable remoteObservable = null;
	private static IAuthorizeGateway authorizationGateway = null;
	static private RaceServerDAO raceReservationServerDAO = null;
	public static List<GatewayObject> gatewaysXML;
	private static List<IRaceServerGateway> appGateways= null;

	public ReservationRaceServer(String args[]) throws RemoteException 
	{
		super();
		this.remoteObservable = new RemoteObservable();
		this.parse();
		this.fillRacesCache();	
	}
	
	private TreeMap<String, Map<String, RaceRMIDTO>> getRacesCache()
	{
		System.out.println("RRCgetRacesCache: "+ racesCache.size());
		return racesCache;
	}
	
	private void fillRacesCache()
	{
		racesCache = new TreeMap<String, Map<String, RaceRMIDTO>>();
		raceMap = new TreeMap<String,RaceRMIDTO>();
		List<raceReservationServer.raceServerGateway.RaceDO> list = new ArrayList<raceReservationServer.raceServerGateway.RaceDO>();
		raceReservationServer.raceServerGateway.RaceDO race = null;
		for (int i = 0;i < appGateways.size(); i++)
		{
			list = appGateways.get(i).getRaces();
			String serverName = appGateways.get(i).getServer();
			RaceServerDAO raceReservationServerDAO = RaceServerDAO.getInstance();
			raceReservationServerDAO.connect();
			int numRaces = list.size();
			for(int j = 0; j < numRaces; j++)
			{
				race = list.get(j);
				int numReserv = raceReservationServerDAO.getPlacesCount(serverName, race.getName());
				int availablePlaces = list.get(j).getaAvailablePlaces();
				availablePlaces = availablePlaces - numReserv;
				raceRmiDto = new RaceRMIDTO(serverName, race.getName(), race.getDistance(), race.getDate(), availablePlaces);
				raceMap.put(race.getName(), raceRmiDto);
				racesCache.put(serverName, raceMap);
				System.out.println("RRC carrera:" + j);
			}
			racesCache.put(serverName, raceMap);
			raceReservationServerDAO.disconnect();
			raceMap = new TreeMap<String,RaceRMIDTO>();
		}
	}
	
	@Override
	public void addRemoteObserver(IRemoteObserver observer) throws RemoteException
	{
		remoteObservable.addRemoteObserver(observer);
	}

	@Override
	public void deleteRemoteObserver(IRemoteObserver observer) throws RemoteException
	{
		remoteObservable.deleteRemoteObserver(observer);
	}

	public void notifyRemoteObservers(Object arg0)  throws RemoteException
	{
		 
		 remoteObservable.notifyRemoteObservers(arg0);
	}
	@Override
	public RunnerRMIDTO login(String user, String pass) throws ValidationException,
			RemoteException 
	{
		RunnerDO runner = null;
		runner = authorizationGateway.login(user, pass);
		return new RunnerRMIDTO(runner.getUsername(), runner.getPassword(),runner.getName(),runner.getAge(),runner.getSex());
	}

	@Override
	public List<RaceRMIDTO> getRaces() throws RemoteException 
	{
		List<RaceRMIDTO> raceList = new ArrayList<RaceRMIDTO>();
		for (Iterator iterator = racesCache.values().iterator();iterator.hasNext();)
		{
			raceMap= (TreeMap<String, RaceRMIDTO>) iterator.next();
			for (Iterator iterator2 = raceMap.values().iterator();iterator2.hasNext();)
			{
				raceList.add((RaceRMIDTO) iterator2.next());
			}
		}
		return raceList;
	}
	
	public static void main(String[] args) throws RemoteException
	{	
		IReservationRaceServer objServidor = new ReservationRaceServer(args);
		String name = "//" + args[0] + ":" + args[1] + "/" + args[5];
		try 
		{ 		
			Naming.rebind(name, objServidor); 
			System.out.println("Server '"+ name + "' active and waiting..."); 
		} 
		catch (Exception e) 
		{ 
			System.err.println("Server exception: " + e.getMessage()); 
			e.printStackTrace(); 
		}
		String uri = null;
		if (args[4].equals("ws"))
		{
			uri = args[3];
		}
		else if (args[4].equals("rmi"))
		{
			uri = "//" + args[0] + ":" + args[1]+"/" + args[2];
		}
		System.out.println(uri);
		authorizationGateway = AuthorizationGatewayFactory.getInstance().getAuthGateway(uri, args[4]);
	}

	@Override
	public void reservePlace(String runnerName, String raceServer,
			String raceName) throws SQLException 
	{
		RaceServerDAO raceReservationServerDAO = RaceServerDAO.getInstance();
        RaceRMIDTO race = null;
        
        try
        {
                raceReservationServerDAO.connect();
        }
        catch (Exception e)
        {
                e.printStackTrace();
        }
        
        /*raceMap = racesCache.get(raceServer);
        race = raceMap.get(raceName);
        raceMap.remove(race);*/
        
        race = ((Map<String, RaceRMIDTO>)racesCache.get(raceServer)).get(raceName);
        
        if (race.getAvailablePlaces() > 0)
        {
                raceReservationServerDAO.reservePlace(runnerName, raceServer, raceName);
                //RaceRMIDTO raceRMIDTO = ((Map<String, RaceRMIDTO>)racesCache.get(raceServer)).get(raceName);
                race.decAvailablePlaces(1);
                //cogiendo de la tabla y decrementando resultado NO CORRECTO
                //race.decAvailablePlaces(1);
                //raceMap.put(raceServer, race);
                //racesCache.put(raceServer, raceMap);
                raceReservationServerDAO.disconnect();
        }
        raceReservationServerDAO.disconnect();
        remoteObservable.notifyRemoteObservers(race);
	}
	
	public void parse()
	{
		String serviceUri = "";
		appGateways = new ArrayList<IRaceServerGateway>();
		SAXParserFactory factory = SAXParserFactory.newInstance();        
	    factory.setValidating(true);
	    
	    try 
	    {
	    	System.out.println("Prueba de SAX");          
	    	SAXParser saxParser = factory.newSAXParser();
	        RaceServerGatewaysSAXHandler handler = new RaceServerGatewaysSAXHandler();                        
	        saxParser.parse("src/raceReservationServer/saxParser/gateway.xml", handler);
	        
	         gatewaysXML = handler.getGatewaysList();
	    } 
	    catch (Exception e) 
	    {
	        System.out.println("Error -> Main():" + e.getMessage());
	        e.printStackTrace();
	    }
	    RaceServerGatewayFactory raceServerGatewayFactory = RaceServerGatewayFactory.getInstance();
	    for  (int i=0; i<gatewaysXML.size();i++)
      	{
      		GatewayObject gatewayXML = gatewaysXML.get(i);
      		List <String> details = gatewayXML.getDetails();
			for(int j = 0; j < details.size(); j++)
			{
				serviceUri = serviceUri + " " + details.get(j);
			}
			serviceUri = serviceUri + " " + gatewayXML.getServiceName();
			String tech = gatewayXML.getTechnology();
      		//Get a gateway from the xml file and with the details create a raceServer gateway
	  		IRaceServerGateway gateway = raceServerGatewayFactory.getRaceServerGateway(serviceUri, tech);
	  		appGateways.add(gateway);
	  		serviceUri = "";
      	}
	}
}

